#ifndef MESSAGE_INFO_HPP
#define MESSAGE_INFO_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <iostream>
#include <cmath>

#define MSG_SEND_IMMEDIATELY    -1.0f
#define NO_EXTRA_INFO           0

namespace smeg {
    namespace core {

////////////////////////////////////////////////////////////
// Struct defining a message.
////////////////////////////////////////////////////////////
struct MessageInfo 
{
    // Message can be dispatched directly (value <= 0) or later in time
    float           m_fDelay;

    // IDs are int value of entity pointers
    int             m_iSenderID;
    int             m_iReceiverID;

    int             m_iMessageType;

    void*           m_pExtraInfo;
    
    ////////////////////////////////////////////////////////////
    /// Constructors
    ///
    ////////////////////////////////////////////////////////////
    MessageInfo() :
        m_fDelay(MSG_SEND_IMMEDIATELY),
        m_iSenderID(-1),
        m_iReceiverID(-1),
        m_iMessageType(-1),
        m_pExtraInfo(NO_EXTRA_INFO)
    {}
        
    MessageInfo(    float _fDelay,
                    int _iSenderID,
                    int _iReceiverID,
                    int _iMessageType,
                    void* _pExtraInfo = NO_EXTRA_INFO) :
        m_fDelay( _fDelay ),
        m_iSenderID(_iSenderID),
        m_iReceiverID(_iReceiverID),
        m_iMessageType(_iMessageType),
        m_pExtraInfo( _pExtraInfo )
    {}
};

// A priority queue will store MessageInfo by their dispatch time,
// we need to overload operators < and == to sort the MessageInfo and avoid duplicates
// Two message with same IDs and type must be sent appart from at least fSmallestDelay
const float fSmallestDelay = 0.25f;

inline bool operator==( const MessageInfo& _m1, const MessageInfo& _m2 ) {
    return ( fabs( _m1.m_fDelay - _m2.m_fDelay ) < fSmallestDelay &&
        _m1.m_iReceiverID == _m2.m_iReceiverID &&
        _m1.m_iSenderID == _m2.m_iSenderID &&
        _m1.m_iMessageType == _m2.m_iMessageType );
}

inline bool operator<( const MessageInfo& _m1, const MessageInfo& _m2 ) {
    if ( _m1.m_fDelay == _m2.m_fDelay ) {
        return false;
    } else {
        return _m1.m_fDelay < _m2.m_fDelay;
    }
}

inline std::ostream& operator<<( std::ostream& o, const MessageInfo& _msg ) {
    o << "Message type : " << _msg.m_iMessageType << 
        ", From " << _msg.m_iSenderID << ", To " << _msg.m_iReceiverID <<
        ", Delayed " << _msg.m_fDelay;

    return o;
}

// Helper function to cast the extra info in a message to an appropriate type
template <typename T>
T* CastMessageInfoTo(const MessageInfo& _msg) {
    return static_cast<T*>(_msg.m_pExtraInfo);
}

    } // namespace core
} // namespace smeg

#endif // MESSAGE_INFO_HPP